﻿Imports System.IO
Imports System.Text.RegularExpressions

Public Class HeapStatParser


    Private Shared hexPattern As New Regex("[0-9a-fA-F]{8}")
    Private Shared summaryPattern As New Regex("^Total [0-9]{1,8} objects")
    Private Shared headerPattern As New Regex("Statistics:\s*?MT\s*?Count\s*?TotalSize\s*?Class Name")
    Private Shared rowPattern As New Regex("^([0-9a-fA-F]{8})\s*?([0-9]{1,9})\s*?([0-9]{1,9})\s(.*?)$")

    Public Shared Function Parse(ByVal text As String) As HeapSnapshot
        'look for results table header(s)
        'multiple (take first fow now, prompt later?)
        Dim startIndex As Integer
        Dim headerMatches As MatchCollection = headerPattern.Matches(text)
        If headerMatches.Count = 0 Then
            'none: assume raw content of table is posted and look for first rows with hexAddress as first line (MT)
            Dim hexMatches As MatchCollection = hexPattern.Matches(text)
            If hexMatches.Count > 0 Then
                startIndex = hexMatches.Item(0).Index
            Else
                MessageBox.Show("No potential dumpheap results found in text")
                Return Nothing
            End If

        ElseIf headerMatches.Count > 1 Then
            MessageBox.Show("Multiple results found in text. Taking first one")
            startIndex = headerMatches.Item(0).Index + headerMatches.Item(0).Length
        Else
            'one header found
            ' process all lines after as results
            startIndex = headerMatches.Item(0).Index + headerMatches.Item(0).Length
        End If

        'get substring of text  from start
        Dim section As String = text.Substring(startIndex)

        Dim reader As New StringReader(section)
        Dim snapshot As New HeapSnapshot()
        Dim emptyLineCount As Integer = 0

        Dim line As String = reader.ReadLine()
        Do While Not line Is Nothing
            If summaryPattern.IsMatch(line) Then Exit Do
            'allow one empty line
            If String.IsNullOrWhiteSpace(line) Then
                emptyLineCount += 1
                If emptyLineCount > 1 Then Exit Do
                line = reader.ReadLine()
                Continue Do
            End If

            Dim rowMatch As Match = rowPattern.Match(line)
            If Not rowMatch.Success Then Exit Do
            Dim row As New HeapSnapshotItem() With {.MT = rowMatch.Groups.Item(1).Value,
                                                    .Count = CInt(rowMatch.Groups.Item(2).Value),
                                                    .Size = CInt(rowMatch.Groups.Item(3).Value),
                                                    .TypeName = rowMatch.Groups.Item(4).Value}

            snapshot.Items.Add(row)

            line = reader.ReadLine()
        Loop

        Return snapshot

    End Function

End Class
